package com.lambkit.core.event;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.log.Log;
import com.lambkit.core.event.annotation.Listener;

import java.util.Collections;
import java.util.Comparator;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * @author yangyong(孤竹行)
 */
public class EventBus implements IEventBus {
    private static final Log log = Log.get(EventBus.class);

    protected final CopyOnWriteArrayList<IEventListener> listeners = new CopyOnWriteArrayList<>();

    @Override
    public void register(Class<? extends IEventListener> listener) {
        for (IEventListener ml : listeners) {
            if (listener == ml.getClass()) {
                return;
            }
        }

        IEventListener eventListener = ReflectUtil.newInstance(listener);
        if (eventListener == null) {
            return;
        }

        listeners.add(eventListener);

        Collections.sort(listeners, new Comparator<IEventListener>() {
            @Override
            public int compare(IEventListener o1, IEventListener o2) {
                Listener l1 = o1.getClass().getAnnotation(Listener.class);
                Listener l2 = o2.getClass().getAnnotation(Listener.class);
                return l1.weight() - l2.weight();
            }
        });
    }

    @Override
    public void unregister(Class<? extends IEventListener> listener) {
        IEventListener eventListener = null;
        for (IEventListener ml : listeners) {
            if (listener == ml.getClass()) {
                eventListener = ml;
                break;
            }
        }

        if(eventListener != null) {
            listeners.remove(eventListener);
        }
    }

    @Override
    public void post(IEvent event) {
        BlockingQueue<IEventListener> queue = new LinkedBlockingQueue<>();
        for (IEventListener listener : listeners) {
            //listener.onEvent(event);
            queue.add(listener);
        }
        while (!queue.isEmpty()) {
            IEventListener listener = queue.poll();
            listener.onEvent(event);
        }
    }
}
